//! Module for chess piece definitions and rules
//!
//! This module defines all the piece types in Chinese Chess (Xiangqi)
//! and their movement rules.

use serde::{Serialize, Deserialize};
use crate::{Position, Side};

/// Represents the type of chess piece
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum PieceType {
    /// 将/帅 - General/King
    General,
    /// 士/仕 - Advisor
    Advisor,
    /// 象/相 - Elephant
    Elephant,
    /// 马/馬 - Horse
    Horse,
    /// 车/車 - Chariot
    Chariot,
    /// 炮/砲 - Cannon
    Cannon,
    /// 兵/卒 - Soldier/Pawn
    Soldier,
}

/// Represents a chess piece with its type and side
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Piece {
    pub piece_type: PieceType,
    pub side: Side,
}

impl Piece {
    /// Create a new piece
    pub fn new(piece_type: PieceType, side: Side) -> Self {
        Piece { piece_type, side }
    }

    /// Get the Unicode character representation of the piece
    pub fn to_char(&self) -> char {
        match (self.side, self.piece_type) {
            // Red pieces (traditional Chinese characters)
            (Side::Red, PieceType::General) => '帥',
            (Side::Red, PieceType::Advisor) => '仕',
            (Side::Red, PieceType::Elephant) => '相',
            (Side::Red, PieceType::Horse) => '傌',
            (Side::Red, PieceType::Chariot) => '俥',
            (Side::Red, PieceType::Cannon) => '炮',
            (Side::Red, PieceType::Soldier) => '兵',
            
            // Black pieces (traditional Chinese characters)
            (Side::Black, PieceType::General) => '將',
            (Side::Black, PieceType::Advisor) => '士',
            (Side::Black, PieceType::Elephant) => '象',
            (Side::Black, PieceType::Horse) => '馬',
            (Side::Black, PieceType::Chariot) => '車',
            (Side::Black, PieceType::Cannon) => '砲',
            (Side::Black, PieceType::Soldier) => '卒',
        }
    }

    /// Get the value of the piece for evaluation purposes
    pub fn value(&self) -> i32 {
        match self.piece_type {
            PieceType::General => 6000,
            PieceType::Advisor => 120,
            PieceType::Elephant => 120,
            PieceType::Horse => 270,
            PieceType::Chariot => 600,
            PieceType::Cannon => 285,
            PieceType::Soldier => 30,
        }
    }

    /// Check if the piece can move to the palace
    pub fn can_move_in_palace(&self) -> bool {
        matches!(self.piece_type, 
            PieceType::General | 
            PieceType::Advisor
        )
    }

    /// Check if the piece is restricted to its own side of the board
    pub fn is_restricted_to_side(&self) -> bool {
        matches!(self.piece_type, 
            PieceType::General | 
            PieceType::Advisor | 
            PieceType::Elephant
        )
    }
}

/// Check if a position is within the palace boundaries for a given side
pub fn is_in_palace(pos: &Position, side: Side) -> bool {
    let file_valid = pos.file >= 3 && pos.file <= 5;
    
    match side {
        Side::Red => file_valid && pos.rank <= 2,
        Side::Black => file_valid && pos.rank >= 7,
    }
}

/// Check if a soldier has crossed the river
pub fn has_crossed_river(pos: &Position, side: Side) -> bool {
    match side {
        Side::Red => pos.rank > 4,
        Side::Black => pos.rank < 5,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_piece_creation() {
        let red_general = Piece::new(PieceType::General, Side::Red);
        assert_eq!(red_general.piece_type, PieceType::General);
        assert_eq!(red_general.side, Side::Red);
    }

    #[test]
    fn test_piece_to_char() {
        let red_general = Piece::new(PieceType::General, Side::Red);
        let black_general = Piece::new(PieceType::General, Side::Black);
        
        assert_eq!(red_general.to_char(), '帥');
        assert_eq!(black_general.to_char(), '將');
    }

    #[test]
    fn test_is_in_palace() {
        // Red palace positions
        assert!(is_in_palace(&Position { file: 3, rank: 0 }, Side::Red));
        assert!(is_in_palace(&Position { file: 4, rank: 1 }, Side::Red));
        assert!(is_in_palace(&Position { file: 5, rank: 2 }, Side::Red));
        
        // Black palace positions
        assert!(is_in_palace(&Position { file: 3, rank: 9 }, Side::Black));
        assert!(is_in_palace(&Position { file: 4, rank: 8 }, Side::Black));
        assert!(is_in_palace(&Position { file: 5, rank: 7 }, Side::Black));
        
        // Outside palace
        assert!(!is_in_palace(&Position { file: 2, rank: 0 }, Side::Red));
        assert!(!is_in_palace(&Position { file: 4, rank: 3 }, Side::Red));
        assert!(!is_in_palace(&Position { file: 4, rank: 6 }, Side::Black));
    }

    #[test]
    fn test_has_crossed_river() {
        // Red soldier
        assert!(!has_crossed_river(&Position { file: 0, rank: 3 }, Side::Red));
        assert!(has_crossed_river(&Position { file: 0, rank: 5 }, Side::Red));
        
        // Black soldier
        assert!(!has_crossed_river(&Position { file: 0, rank: 6 }, Side::Black));
        assert!(has_crossed_river(&Position { file: 0, rank: 4 }, Side::Black));
    }
}